#pragma once

#include "Object.h"
#include "aoi/AoiActor.h"
#include "tile/TileActor.h"
#include "Script/LuaHookEvent.h"

class MapInstance;

class LocatableObject : public Object, public AoiActor, public TileActor,
	public WheelTimerOwner, public WheelRoutineType
{
public:
	LocatableObject(OBJECT_TYPE objType);
	virtual ~LocatableObject();

	virtual void Update(uint64 diffTime);

	bool PushToWorld(MapInstance* pMapInstance);
	void OutOfWorld(MapInstance* pMapInstance);
	void RemoveFromWorld(MapInstance* pMapInstance);
	void Delete(MapInstance* pMapInstance);

	virtual void OnPrePushToWorld() {}
	virtual void OnPushToWorld() {}
	virtual void OnPreLeaveWorld() {}
	virtual void OnLeftWorld() {}
	virtual void OnDelete() {}

	void SetPosition(const vector3f& pos);
	void SetDirection(const vector3f& dir);
	void SetOrientation(float o);

	void Relocate(const vector3f& pos);
	void Relocate(const vector3f& pos, const vector3f& dir);
	void Relocate(const vector3f& pos, float o);

	virtual void OnChangePosition() {}

	virtual void UpdateActive();
	virtual bool IsDeletable();

	virtual void BuildCreatePacketForPlayer(INetPacket& pck, Player* pPlayer);

	void PushMessage(const INetPacket& pck, bool isToSet = false, bool hasSelf = true) const;
	void SendMessageToSet(const INetPacket& pck, bool hasSelf = true) const;

	void SendValueUpdate();

	void Disappear(uint64 delayTime);
	void FastDisappear();

	float GetDistance(const vector3f& pos) const {
		return m_position.Distance(pos);
	}
	float GetDistance2D(const vector3f& pos) const {
		return m_position.Distance2D(pos);
	}
	float GetDistanceSq(const vector3f& pos) const {
		return m_position.DistanceSq(pos);
	}
	float GetDistance2DSq(const vector3f& pos) const {
		return m_position.Distance2DSq(pos);
	}

	float GetDistance(const LocatableObject* obj) const {
		return GetDistance(obj->GetPosition());
	}
	float GetDistance2D(const LocatableObject* obj) const {
		return GetDistance2D(obj->GetPosition());
	}
	float GetDistanceSq(const LocatableObject* obj) const {
		return GetDistanceSq(obj->GetPosition());
	}
	float GetDistance2DSq(const LocatableObject* obj) const {
		return GetDistance2DSq(obj->GetPosition());
	}

	MapInstance* GetMapInstance() const { return m_pMapInstance; }
	InstGUID GetInstGuid() const { return m_instGuid; }
	uint32 GetMapId() const { return m_instGuid.MAPID; }
	uint32 GetMapType() const { return m_instGuid.TID; }

	const vector3f& GetPosition() const { return m_position; }
	const vector3f& GetDirection() const { return m_direction; }
	const float GetOrientation() const { return m_direction.Calc2DAngle(); }

	bool IsAlive() const { return m_deleteExpireTime == 0; }
	bool IstobeDisappear() const { return m_istobeDisappear; }

protected:
	virtual WheelTimerMgr *GetWheelTimerMgr();

	MapInstance* m_pMapInstance;
	InstGUID m_instGuid;

	vector3f m_position;
	vector3f m_direction;

	uint64 m_lastUpdateTime;
	uint64 m_deleteExpireTime;

	bool m_isDisappear;
	bool m_istobeDisappear;

public:
	bool IsVisibleByPlayer(const Player* pPlayer);

public:
	void ObjectHookEvent_OnSendMessage(const char* funcName, const LuaTable& args) const;
public:
	uint32 AttachObjectHookInfo(LuaTable&& t);
	void DetachObjectHookInfo(uint32 key);
protected:
	void DestructAllObjectHookInfos();
	void CleanObjectHookInfos();
	uint32 NewObjectHookKey() { return ++m_objectHookUniqueKey; }
	uint32 m_objectHookUniqueKey;
	std::map<uint32, ObjectHookInfo*> m_objectHookInfos;
	std::vector<uint32> m_gcObjectHookKeys;

public:
	void InitLuaEnv();
	const LuaRef& GetVariables() const;
	virtual AIBlackboard &GetBlackboard();
	static void InitBlackboard(lua_State* L);
protected:
	virtual void SubInitLuaEnv() = 0;
	struct Blackboard : public AIBlackboard {
		LuaRef m_variables;
	} m_blackboard;
};
